Skip to content

fix(h2): return Poll::Pending when poll_capacity is not ready in UpgradedSendStreamTask#4050

Open
abbshr wants to merge 1 commit intohyperium:masterfrom
abbshr:fix/poll_capacity_bypass_backpressure
Open

fix(h2): return Poll::Pending when poll_capacity is not ready in UpgradedSendStreamTask#4050
abbshr wants to merge 1 commit intohyperium:masterfrom
abbshr:fix/poll_capacity_bypass_backpressure

Conversation

@abbshr
Copy link
Copy Markdown

@abbshr abbshr commented Apr 9, 2026

Fix #4049

Fix a backpressure bypass bug in UpgradedSendStreamTask::tick() where poll_capacity() returning Poll::Pending caused a 'break 'capacity' that fell through to rx.poll_next() -> send_data(), pushing data into the h2 send buffer without available capacity. This broke the HTTP/2 flow control chain, causing unbounded memory growth (OOM) when downstream consumers were slower than upstream producers.

The fix changes 'break 'capacity' to 'return Poll::Pending', which correctly suspends the task until a WINDOW_UPDATE frame restores send capacity. The now-unused 'capacity label is also removed.

This bug was introduced in hyper v1.8.0 (PR #3967) and affects v1.8.0, v1.8.1, and v1.9.0. A single HTTP/2 CONNECT tunnel with asymmetric upstream/downstream speeds could trigger OOM within seconds.

Add four integration tests covering H2 CONNECT backpressure scenarios:

  • h2_connect_backpressure_respected: small window + large data transfer
  • h2_connect_zero_window_then_release: normal path regression guard
  • h2_connect_reset_during_backpressure: RST_STREAM error propagation
  • h2_connect_backpressure_bidirectional: bidirectional data + backpressure

…adedSendStreamTask

Fix a backpressure bypass bug in UpgradedSendStreamTask::tick() where
poll_capacity() returning Poll::Pending caused a 'break 'capacity' that
fell through to rx.poll_next() -> send_data(), pushing data into the h2
send buffer without available capacity. This broke the HTTP/2 flow
control chain, causing unbounded memory growth (OOM) when downstream
consumers were slower than upstream producers.

The fix changes 'break 'capacity' to 'return Poll::Pending', which
correctly suspends the task until a WINDOW_UPDATE frame restores send
capacity. The now-unused 'capacity label is also removed.

This bug was introduced in hyper v1.8.0 (PR hyperium#3967) and affects
v1.8.0, v1.8.1, and v1.9.0. A single HTTP/2 CONNECT tunnel with
asymmetric upstream/downstream speeds could trigger OOM within seconds.

Add four integration tests covering H2 CONNECT backpressure scenarios:
- h2_connect_backpressure_respected: small window + large data transfer
- h2_connect_zero_window_then_release: normal path regression guard
- h2_connect_reset_during_backpressure: RST_STREAM error propagation
- h2_connect_backpressure_bidirectional: bidirectional data + backpressure
@abbshr
Copy link
Copy Markdown
Author

abbshr commented Apr 9, 2026

cc @seanmonstar
Thanks for reviewing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTP/2 CONNECT Upgraded stream bypasses H2 flow-control backpressure, causing unbounded memory growth (OOM)

1 participant